package library

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"net/url"
	"regexp"
	"strings"
	"vip_video/configx"
	"vip_video/models"
)

type ParseVideoLibrary struct {
	handle      map[int]map[string]func(url string, pv *ParseVideoLibrary) (string, error)
	_type       int
	_handleName string
	_config     *configx.Config
}

func NewParseVideo() *ParseVideoLibrary {
	return &ParseVideoLibrary{
		handle: map[int]map[string]func(url string, pv *ParseVideoLibrary) (string, error){
			9: {
				"shyVideo": shyVideo,
			},
			4: {
				"shyVideo": shyVideo,
			},
			2: {
				"shyVideo": shyVideo,
			},
			24: {
				"nivod": nivod,
			},
			25: {
				"pan123": pan123,
			},
		},
	}
}

func (pvl *ParseVideoLibrary) WithConfig(config *configx.Config) *ParseVideoLibrary {
	pvl._config = config
	return pvl
}

func (pvl *ParseVideoLibrary) WithType(_type int) *ParseVideoLibrary {
	pvl._type = _type
	return pvl
}

func (pvl *ParseVideoLibrary) WithHandleName(_handleName string) *ParseVideoLibrary {
	pvl._handleName = _handleName
	return pvl
}

// nivod https://www.nivod.vip
func nivod(u string, pv *ParseVideoLibrary) (string, error) {
	data, err := Get(u)
	if err != nil {
		return "", errors.New(fmt.Sprintf("请求网络失败:%s", err.Error()))
	}
	q, err := goquery.NewDocumentFromReader(strings.NewReader(string(data)))
	if err != nil {
		return "", errors.New("解析网页失败")
	}
	script := q.Find(".player-box-main").Find("script").Text()
	if script == "" {
		return "", errors.New("解析数据失败")
	}
	re := regexp.MustCompile(`^var.+player_aaaa={.+}$`)
	matches := re.FindAllString(script, -1)
	if len(matches) <= 0 {
		return "", errors.New("解析失败,未取得播放连接")
	}
	replaceRe := regexp.MustCompile(`var.+player_aaaa=`)
	fmt.Println("json 数据", matches[0])
	j := replaceRe.ReplaceAllString(matches[0], "")
	fmt.Println("替换后的 json 数据:", j)
	var d NivodM3u8Json
	if err := json.Unmarshal([]byte(j), &d); err != nil {
		return "", errors.New("解析视频出错,解析 json 数据失败")
	}
	return d.Url, nil
}

// pan123 123网盘解析
func pan123(u string, pv *ParseVideoLibrary) (string, error) {
	//先获取网页数据
	urlArr := strings.Split(u, "/")
	shareKey := urlArr[len(urlArr)-1]
	if strings.EqualFold(shareKey, "") {
		return "", errors.New("解析密钥失败")
	}
	listUrl := fmt.Sprintf("https://www.123684.com/b/api/share/video/play/list?Page=1&limit=50&ParentFileId=0&shareKey=%s&next=-1&orderDirection=asc&orderBy=file_name", shareKey)
	//先请求 list 接口获取数据
	listData, err := Get(listUrl)
	if err != nil {
		return "", errors.New("获取123网盘数据失败")
	}
	var pan123Model models.Pan123ListModel
	if err := json.Unmarshal(listData, &pan123Model); err != nil {
		return "", errors.New("解析123网盘数据失败")
	}
	if pan123Model.Code != 0 {
		return "", errors.New(pan123Model.Message)
	}
	if len(pan123Model.Data.List) <= 0 {
		return "", errors.New("数据不存在")
	}
	firstList := pan123Model.Data.List[0]
	eTag := firstList.Etag
	size := firstList.Size
	//请求详情接口
	infoUrl := fmt.Sprintf("https://www.123684.com/b/api/video/play/info?etag=%s&size=%d&from=1&shareKey=%s", eTag, size, shareKey)
	infoData, err := Get(infoUrl)
	if err != nil {
		return "", errors.New("获取123网盘视频详情失败")
	}
	var pan123InfoModel models.Pan123InfoModel
	if err := json.Unmarshal(infoData, &pan123InfoModel); err != nil {
		return "", errors.New("解析视频详情失败")
	}
	if pan123InfoModel.Code != 0 {
		return "", errors.New(pan123InfoModel.Message)
	}
	if len(pan123InfoModel.Data.VideoPlayInfo) <= 0 {
		return "", errors.New("解析123网盘视频失败,无播放链接")
	}
	return pan123InfoModel.Data.VideoPlayInfo[0].URL, nil
}

// shyVideo http://shybot.top/video/jx/md/?ShyToken=shy_xvkong.shybot.cc
func shyVideo(u string, pv *ParseVideoLibrary) (string, error) {
	fmt.Println("视频网页地址:", u)
	parseUrl := &url.URL{
		Scheme: "http",
		Host:   "shybot.top",
		Path:   "video/jx/",
	}
	query := parseUrl.Query()
	query.Set("url", u)
	query.Set("play", "2")
	query.Set("ShyToken", pv._config.Shybot.Token)
	parseUrl.RawQuery = query.Encode()
	data, err := Get(parseUrl.String())
	if err != nil {
		return "", errors.New(fmt.Sprintf("请求网络失败:%s", err.Error()))
	}
	fmt.Println("返回的json数据:", string(data))
	if IsYouKuUrl(u) { //优酷
		var detail []models.Urls
		if err := json.Unmarshal(data, &detail); err != nil {
			fmt.Println(err.Error())
			return "", errors.New("解析数据失败")
		}
		return detail[0].Url, nil
	} else if IsBiliBiliUrl(u) { //bilibili
		var detail models.BiliBiliShybotModel
		if err := json.Unmarshal(data, &detail); err != nil {
			fmt.Println(err.Error())
			return "", errors.New("解析数据失败")
		}
		return detail.Url, nil
	} else { //默认
		var detail models.DefaultShybotModel
		if err := json.Unmarshal(data, &detail); err != nil {
			fmt.Println(err.Error())
			return "", errors.New("解析数据失败")
		}
		return detail.Url, nil
	}
}

// Parse 统一解析方法入口
func (pvl *ParseVideoLibrary) Parse(url string) (string, error) {
	handleList, ok := pvl.handle[pvl._type]
	if !ok {
		return "", errors.New("未找到解析方法,请反馈给管理员")
	}
	fun, ok := handleList[pvl._handleName]
	if !ok {
		return "", errors.New("未找到解析方法,请反馈给管理员")
	}
	return fun(url, pvl)
}
